local skynet = require "skynet"
local filename = "slotmgr.lua"
local filelog = require "filelog"
local queue = require "skynet.queue"
local base = require "base"
local redisdao = require "redisdao"
local tabletool = require "tabletool"
local json = require "cjson"
json.encode_sparse_array(true,1,1)

local SlotTool = require "slottool"
require "brnnenum"

--有牛牌表
local cowcards_list = require "cowcards_list"

------------
--枚举类

--扑克牌组数
local CardPairNum = 1           --1副牌，每副52张

--牌数组偏移
local CardOffset = 0

--扑克牌定义
--百位表示花色：1方块 2梅花 3红桃 4黑桃;末2位表示牌值1-A 11-J 12-Q 13—K 2~10-2~10
local CardData = {
    101,102,103,104,105,106,107,108,109,110,111,112,113,
    201,202,203,204,205,206,207,208,209,210,211,212,213,
    301,302,303,304,305,306,307,308,309,310,311,312,313,
    401,402,403,404,405,406,407,408,409,410,411,412,413,
}

--系统输钱上限基值,默认10万
local SystemLoseLimit_Base = 1000000

--系统输钱上限控制系数
local SystemLoseLimit_Factor = 0.08

--开奖类型
local LotteryType = {
    LOTTERY_TYPE_SYSTEM_WIN = 1,   --系统必赢
    LOTTERY_TYPE_SYSTEM_LOSE = 2,  --系统必输
    LOTTERY_TYPE_NORMAL = 3,       --正常开奖
}

--图标类型
local Picture_type = {
    PICTURE_TYPE_NORMAL = 1,    --普通图标
}

--图标subid（不计类型）
local Picture_subid = {
    101,    --闲家1赢
    102,    --闲家2赢
    103,    --闲家3赢
    104,    --闲家4赢
    105,    --庄家通杀
}

--图标id
local Picture_id = {
    1101,    --闲家1赢
    1102,    --闲家2赢
    1103,    --闲家3赢
    1104,    --闲家4赢
    1105,    --庄家通杀
}

--特殊奖励定义
local SpecialPrize = {
    SPECIAL_PRIZE_MEI_NIU = 0,          --没牛
    SPECIAL_PRIZE_NIU_YI = 1,           --牛一
    SPECIAL_PRIZE_NIU_ER = 2,           --牛二
    SPECIAL_PRIZE_NIU_SAN = 3,          --牛三
    SPECIAL_PRIZE_NIU_SI = 4,           --牛四
    SPECIAL_PRIZE_NIU_WU = 5,           --牛五
    SPECIAL_PRIZE_NIU_LIU = 6,          --牛六
    SPECIAL_PRIZE_NIU_QI = 7,           --牛七
    SPECIAL_PRIZE_NIU_BA = 8,           --牛八
    SPECIAL_PRIZE_NIU_JIU = 9,          --牛九
    SPECIAL_PRIZE_NIU_NIU = 10,         --牛牛
    SPECIAL_PRIZE_SHUNZI_NIU = 11,      --顺子牛
    SPECIAL_PRIZE_TONGHUA_NIU = 12,     --同花牛
    SPECIAL_PRIZE_HULU_NIU = 13,        --葫芦牛
    SPECIAL_PRIZE_ZHADAN_NIU = 14,      --炸弹牛
    SPECIAL_PRIZE_WUHUA_NIU = 15,       --五花牛
    SPECIAL_PRIZE_WUXIAO_NIU = 16,      --五小牛
    SPECIAL_PRIZE_TONGHUASHUN_NIU = 17, --同花顺牛
}

--额外奖励类型列表（所有奖励）
--brnnenum.lua中有对应定义
local Extra_prize_type = {

}

----------------------
--数据表，可以改变

--倍率列表
--key为：图标id = 图标类型 + 图标subid
--[1101] = 0 表示：红的赔率为2倍
--
local Odds_list = {
    [1101] = {  --闲1赢
        [SpecialPrize.SPECIAL_PRIZE_MEI_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_YI] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_ER] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_SAN] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_SI] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_WU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_LIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_QI] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_BA] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_JIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_SHUNZI_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_TONGHUA_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_HULU_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_ZHADAN_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_WUHUA_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_WUXIAO_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_TONGHUASHUN_NIU] = 2,
    },     
    [1102] = {  --闲2赢
        [SpecialPrize.SPECIAL_PRIZE_MEI_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_YI] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_ER] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_SAN] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_SI] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_WU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_LIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_QI] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_BA] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_JIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_SHUNZI_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_TONGHUA_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_HULU_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_ZHADAN_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_WUHUA_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_WUXIAO_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_TONGHUASHUN_NIU] = 2,
    },    
    [1103] = {  --闲3赢
        [SpecialPrize.SPECIAL_PRIZE_MEI_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_YI] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_ER] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_SAN] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_SI] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_WU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_LIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_QI] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_BA] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_JIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_SHUNZI_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_TONGHUA_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_HULU_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_ZHADAN_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_WUHUA_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_WUXIAO_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_TONGHUASHUN_NIU] = 2,
    },
    [1104] = {  --闲4赢
        [SpecialPrize.SPECIAL_PRIZE_MEI_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_YI] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_ER] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_SAN] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_SI] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_WU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_LIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_QI] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_BA] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_JIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_SHUNZI_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_TONGHUA_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_HULU_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_ZHADAN_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_WUHUA_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_WUXIAO_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_TONGHUASHUN_NIU] = 2,
    },        
    [1105] = {  --庄通杀
        [SpecialPrize.SPECIAL_PRIZE_MEI_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_YI] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_ER] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_SAN] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_SI] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_WU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_LIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_QI] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_BA] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_JIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_NIU_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_SHUNZI_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_TONGHUA_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_HULU_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_ZHADAN_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_WUHUA_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_WUXIAO_NIU] = 2,
        [SpecialPrize.SPECIAL_PRIZE_TONGHUASHUN_NIU] = 2,
    }   
}

--图标权重列表
--共16种开奖：
-- {闲1赢}，{闲2赢}，{闲3赢}，{闲4赢}
-- {闲1赢，闲2赢}，{闲1赢，闲3赢}，{闲1赢，闲4赢}，{闲2赢，闲3赢}，{闲2赢，闲4赢}，{闲3赢，闲4赢}
-- {闲1赢，闲2赢，闲3赢}，{闲1赢，闲2赢，闲4赢}，{闲1赢，闲3赢，闲4赢}，{闲2赢，闲3赢，闲4赢}
-- {闲1赢，闲2赢，闲3赢，闲4赢}，{庄通杀}
local Weight_list = {
    [21000] = 400,    --闲1赢
    [20100] = 400,    --闲2赢
    [20010] = 400,    --闲3赢
    [20001] = 400,    --闲4赢
    [21100] = 200,    --闲1,2赢
    [21010] = 200,    --闲1,3赢
    [21001] = 200,    --闲1,4赢
    [20110] = 200,    --闲2,3赢
    [20101] = 200,    --闲2,4赢
    [20011] = 200,    --闲3,4赢
    [21110] = 100,    --闲1,2,3赢
    [21101] = 100,    --闲1,2,4赢
    [21011] = 100,    --闲1,3,4赢
    [20111] = 100,    --闲2,3,4赢
    [21111] = 50,     --闲1,2,3,4赢
    [20000] = 50,     --庄通杀
}

--权值项对应倍率列表
local Witem_odds_list = {
    [21000] = {1101},               --闲1赢
    [20100] = {1102},               --闲2赢
    [20010] = {1103},               --闲3赢
    [20001] = {1104},               --闲4赢
    [21100] = {1101,1102},          --闲1,2赢
    [21010] = {1101,1103},          --闲1,3赢
    [21001] = {1101,1104},          --闲1,4赢
    [20110] = {1102,1103},          --闲2,3赢
    [20101] = {1102,1104},          --闲2,4赢
    [20011] = {1103,1104},          --闲3,4赢
    [21110] = {1101,1102,1103},     --闲1,2,3赢
    [21101] = {1101,1102,1104},     --闲1,2,4赢
    [21011] = {1101,1103,1104},     --闲1,3,4赢
    [20111] = {1102,1103,1104},     --闲2,3,4赢
    [21111] = {1101,1102,1103,1104},--闲1,2,3,4赢
    [20000] = {1105},               --庄通杀
}

--系统库存概率表
--S = 库存值
local S_list = {
    [1] = { -- S < -500万
        nohit = 1.00,   --必不中概率
        normal = 0.00,  --正常开奖概率
        hit = 0.00,     --必中概率
    },
    [2] = { -- -500万<=S<-100万
        nohit = 0.80,   --必不中概率
        normal = 0.20,  --正常开奖概率
        hit = 0.00,     --必中概率
    },
    [3] = { -- -100万<=S<-20万
        nohit = 0.60,   --必不中概率
        normal = 0.40,  --正常开奖概率
        hit = 0.00,     --必中概率
    },
    [4] = { -- -20万<=S<-10万
        nohit = 0.30,   --必不中概率
        normal = 0.70,  --正常开奖概率
        hit = 0.00,     --必中概率
    },
    [5] = { -- -10万<=S<200万
        nohit = 0.00,   --必不中概率
        normal = 1.00,  --正常开奖概率
        hit = 0.00,     --必中概率
    },
    [6] = { -- 200万<=S<1000万
        nohit = 0.00,   --必不中概率
        normal = 0.80,  --正常开奖概率
        hit = 0.20,     --必中概率
    },
    [7] = { -- 1000万<=S<5000万
        nohit = 0.00,   --必不中概率
        normal = 0.60,  --正常开奖概率
        hit = 0.40,     --必中概率
    },
    [8] = { -- 5000万<=S<1亿
        nohit = 0.00,   --必不中概率
        normal = 0.50,  --正常开奖概率
        hit = 0.50,     --必中概率
    },
    [9] = { -- S>=1亿
        nohit = 0.00,   --必不中概率
        normal = 0.40,  --正常开奖概率
        hit = 0.60,     --必中概率
    },
}

--特殊奖励权值表
local SPrize_weight_list = {
    
}

--开奖权值表
local Jackpot_weight_list = {
    [0] = {
        [1] = 100,  --中奖励1的权重
        [2] = 0,    --中奖励2的权重
        [3] = 0,    --中奖励3的权重
        [4] = 0,    --中奖励4的权重
        [5] = 0,    --中奖励5的权重
        [6] = 0,    --中奖励6的权重
    },
    [1] = {
        [1] = 80,   --中奖励1的权重
        [2] = 20,   --中奖励2的权重
        [3] = 0,    --中奖励3的权重
        [4] = 0,    --中奖励4的权重
        [5] = 0,    --中奖励5的权重
        [6] = 0,    --中奖励6的权重
    },
    [2] = {
        [1] = 60,   --中奖励1的权重
        [2] = 30,   --中奖励2的权重
        [3] = 10,   --中奖励3的权重
        [4] = 0,    --中奖励4的权重
        [5] = 0,    --中奖励5的权重
        [6] = 0,    --中奖励6的权重
    },
    [3] = {
        [1] = 50,   --中奖励1的权重
        [2] = 30,   --中奖励2的权重
        [3] = 10,   --中奖励3的权重
        [4] = 10,   --中奖励4的权重
        [5] = 0,    --中奖励5的权重
        [6] = 0,    --中奖励6的权重
    },
    [4] = {
        [1] = 40,   --中奖励1的权重
        [2] = 30,   --中奖励2的权重
        [3] = 20,   --中奖励3的权重
        [4] = 10,   --中奖励4的权重
        [5] = 0,    --中奖励5的权重
        [6] = 0,    --中奖励6的权重
    },
    [5] = {
        [1] = 30,   --中奖励1的权重
        [2] = 30,   --中奖励2的权重
        [3] = 20,   --中奖励3的权重
        [4] = 10,   --中奖励4的权重
        [5] = 10,   --中奖励5的权重
        [6] = 0,    --中奖励6的权重
    },
    [6] = {
        [1] = 10,   --中奖励1的权重
        [2] = 20,   --中奖励2的权重
        [3] = 20,   --中奖励3的权重
        [4] = 20,   --中奖励4的权重
        [5] = 20,   --中奖励5的权重
        [6] = 10    --中奖励6的权重
    },
}

--奖池奖励列表
local Jackpot_award_list = {
    [1] = 1,    --获取奖池1%
    [2] = 5,    --获取奖池5%
    [3] = 8,    --获取奖池8%
    [4] = 10,   --获取奖池10%
    [5] = 15,   --获取奖池15%
    [6] = 20,   --获取奖池20%
}


--------------------------
--辅助表

--图标概率表，由权重表生成
local Prob_list = nil

--图标总权值,，由权重表生成
local Total_weight = nil

--预存牌型表,每种5种
local Profile_Cards_List = {
    [21000] = {
        [1] = {{108,406,201,409,303,},{209,311,213,408,313,},{104,302,204,404,410,},{208,109,112,103,301,},{202,212,206,203,113,},},
        [2] = {{108,102,109,312,309,},{408,110,412,210,411,},{205,410,202,203,105,},{204,303,206,304,111,},{403,310,201,313,209,},},
        [3] = {{312,109,205,406,105,},{111,403,413,207,208,},{303,206,313,306,113,},{101,201,106,412,110,},{112,402,211,202,307,},},
        [4] = {{413,403,110,307,306,},{412,109,410,401,211,},{210,212,108,206,107,},{406,304,302,408,209,},{310,208,213,305,308,},},
        [5] = {{312,204,306,211,310,},{307,207,113,411,106,},{108,109,408,206,203,},{301,406,404,201,102,},{107,305,302,403,210,},},
    },    --闲1赢
    [20100] = {
        [1] = {{401,409,213,108,111,},{307,105,301,305,113,},{403,106,104,204,303,},{207,304,206,308,306,},{406,107,212,413,404,},},
        [2] = {{405,102,210,201,209,},{413,311,404,108,401,},{409,207,410,113,104,},{309,204,206,203,412,},{112,106,111,407,301,},},
        [3] = {{101,309,307,404,107,},{210,212,411,209,202,},{405,306,413,111,409,},{311,113,410,302,301,},{406,201,112,206,204,},},
        [4] = {{206,103,309,407,411,},{308,101,110,408,111,},{107,109,310,412,211,},{306,202,304,413,410,},{106,213,307,302,210,},},
        [5] = {{413,111,311,402,409,},{104,304,404,407,213,},{107,302,408,301,204,},{401,108,208,210,211,},{309,113,405,312,308,},},
    },    --闲2赢
    [20010] = {
        [1] = {{412,404,105,203,305,},{202,402,210,313,108,},{211,312,212,411,406,},{103,207,101,112,209,},{403,208,110,306,205,},},
        [2] = {{101,412,309,202,407,},{313,203,402,108,310,},{304,207,403,408,303,},{302,312,404,208,306,},{411,206,104,105,213,},},
        [3] = {{403,213,211,105,313,},{113,203,304,309,201,},{106,404,401,311,212,},{110,410,310,407,102,},{402,107,111,302,405,},},
        [4] = {{211,409,402,407,109,},{203,108,403,110,106,},{202,408,302,405,205,},{101,104,411,309,105,},{312,304,111,207,313,},},
        [5] = {{209,407,413,201,108,},{309,110,302,310,412,},{210,402,207,107,208,},{202,307,204,101,102,},{212,311,313,403,401,},},
    },    --闲3赢
    [20001] = {
        [1] = {{307,113,106,411,410,},{108,205,211,412,312,},{407,413,306,201,111,},{405,104,102,313,107,},{406,303,302,304,101,},},
        [2] = {{113,207,302,410,213,},{411,401,210,405,301,},{303,102,310,408,309,},{204,313,304,105,104,},{412,109,306,205,110,},},
        [3] = {{209,205,305,312,211,},{109,201,401,105,405,},{204,406,310,212,103,},{113,407,404,102,313,},{403,108,307,301,101,},},
        [4] = {{209,208,309,402,313,},{404,202,205,106,411,},{110,203,112,207,204,},{108,102,413,412,403,},{407,302,107,101,303,},},
        [5] = {{207,109,411,104,108,},{313,210,110,211,306,},{208,302,303,101,409,},{402,301,410,205,304,},{204,212,311,412,404,},},
    },    --闲4赢
    [21100] = {
        [1] = {{404,411,105,407,402,},{202,408,210,304,406,},{209,211,312,409,413,},{305,103,310,106,206,},{102,101,401,309,104,},},
        [2] = {{105,405,104,208,113,},{310,306,108,109,301,},{303,311,201,209,111,},{207,411,407,107,101,},{206,403,302,309,401,},},
        [3] = {{312,207,412,109,108,},{402,306,313,101,403,},{407,204,401,212,113,},{308,405,111,304,411,},{311,310,309,107,307,},},
        [4] = {{213,311,103,411,313,},{204,402,309,408,304,},{212,413,208,205,102,},{308,108,207,113,410,},{302,406,101,111,106,},},
        [5] = {{201,113,412,204,111,},{211,304,405,301,408,},{410,308,212,407,302,},{209,101,401,403,107,},{205,207,310,106,213,},},
    },    --闲1,2赢
    [21010] = {
        [1] = {{311,204,113,306,307,},{112,207,202,401,410,},{309,312,302,110,404,},{405,411,211,203,412,},{212,304,208,303,402,},},
        [2] = {{112,410,108,312,203,},{104,313,404,107,303,},{209,307,113,406,211,},{205,305,111,302,210,},{412,405,411,206,403,},},
        [3] = {{213,402,112,106,411,},{301,405,313,104,413,},{102,205,401,105,409,},{113,302,111,207,101,},{107,308,412,406,309,},},
        [4] = {{204,206,306,207,113,},{405,404,409,412,301,},{403,104,402,111,212,},{305,105,110,101,208,},{112,302,307,411,303,},},
        [5] = {{307,310,406,101,309,},{209,208,408,206,305,},{409,401,405,211,306,},{113,205,413,213,111,},{104,210,201,108,308,},},
    },    --闲1,3赢
    [21001] = {
        [1] = {{413,102,403,402,207,},{211,112,410,212,109,},{101,306,106,202,406,},{305,107,401,307,213,},{312,409,201,309,407,},},
        [2] = {{209,409,413,107,213,},{302,104,311,401,204,},{206,313,110,106,201,},{111,412,309,208,306,},{202,405,404,207,303,},},
        [3] = {{409,211,213,102,105,},{402,308,111,107,212,},{310,311,408,204,309,},{104,307,407,103,404,},{208,201,112,304,313,},},
        [4] = {{404,406,311,306,413,},{405,204,101,113,410,},{307,304,402,206,403,},{308,112,210,312,106,},{212,409,108,310,201,},},
        [5] = {{313,107,205,407,103,},{213,109,111,211,206,},{406,204,409,207,306,},{104,113,208,307,412,},{202,209,301,112,101,},},
    },    --闲1,4赢
    [20110] = {
        [1] = {{405,310,104,103,113,},{102,107,202,204,212,},{411,213,408,403,309,},{111,201,313,311,306,},{210,108,203,404,205,},},
        [2] = {{408,209,107,203,111,},{309,307,407,204,206,},{112,312,409,313,113,},{306,102,411,108,401,},{205,207,109,202,410,},},
        [3] = {{406,212,412,308,109,},{311,404,410,401,102,},{105,107,106,408,202,},{211,103,413,206,403,},{201,405,112,307,407,},},
        [4] = {{409,313,402,104,211,},{111,404,110,302,109,},{210,107,407,406,412,},{408,303,312,307,203,},{305,208,411,212,106,},},
        [5] = {{409,106,313,305,403,},{209,201,312,401,413,},{108,410,302,411,211,},{406,113,402,102,304,},{104,208,105,212,110,},},
    },    --闲2,3赢
    [20101] = {
        [1] = {{313,412,311,308,203,},{301,310,113,210,410,},{202,213,411,212,206,},{107,406,205,305,103,},{201,104,306,407,405,},},
        [2] = {{107,205,204,407,313,},{308,302,309,101,102,},{109,405,402,209,202,},{408,110,113,201,304,},{111,401,108,203,409,},},
        [3] = {{111,209,213,311,202,},{403,310,406,102,412,},{105,208,103,312,307,},{308,211,404,104,205,},{408,413,203,207,204,},},
        [4] = {{208,313,213,309,205,},{203,106,409,312,112,},{110,404,413,210,402,},{113,109,407,212,207,},{405,201,401,308,311,},},
        [5] = {{303,302,404,104,205,},{402,305,310,413,308,},{108,309,411,403,209,},{307,113,101,213,406,},{311,304,103,407,105,},},
    },    --闲2,4赢
    [20011] = {
        [1] = {{307,408,309,103,306,},{409,310,304,302,412,},{406,106,206,207,402,},{101,113,111,204,211,},{405,108,203,311,109,},},
        [2] = {{113,101,106,407,202,},{204,104,201,408,110,},{105,102,308,208,406,},{311,111,302,205,410,},{103,303,213,211,212,},},
        [3] = {{204,308,210,302,103,},{111,301,304,110,409,},{104,203,305,106,108,},{402,404,207,309,208,},{109,411,410,303,107,},},
        [4] = {{309,312,202,406,412,},{311,301,307,105,212,},{403,302,206,306,404,},{203,107,310,409,308,},{410,210,402,401,109,},},
        [5] = {{313,206,111,101,108,},{408,109,304,311,310,},{113,103,305,403,208,},{105,404,201,401,402,},{306,102,412,405,308,},},
    },    --闲3,4赢
    [21110] = {
        [1] = {{203,307,204,412,313,},{304,113,208,108,310,},{202,206,410,106,302,},{301,205,209,112,210,},{401,107,411,308,406,},},
        [2] = {{407,112,307,212,110,},{102,302,106,104,306,},{309,111,113,109,210,},{404,108,202,213,303,},{308,403,208,311,304,},},
        [3] = {{103,212,110,206,304,},{201,306,308,406,109,},{213,404,405,210,413,},{107,113,312,102,310,},{211,209,305,409,407,},},
        [4] = {{403,411,111,208,406,},{405,304,211,310,311,},{408,305,313,204,207,},{312,212,213,105,209,},{302,409,107,410,210,},},
        [5] = {{306,409,206,411,203,},{110,213,107,307,212,},{406,407,105,310,412,},{112,303,402,104,202,},{210,106,311,301,205,},},
    },    --闲1,2,3赢
    [21101] = {
        [1] = {{111,205,204,412,106,},{403,110,104,413,211,},{310,309,411,406,101,},{209,102,208,112,405,},{201,105,305,107,108,},},
        [2] = {{201,413,212,405,106,},{110,307,402,111,412,},{204,206,306,308,403,},{401,303,105,103,208,},{406,301,109,313,411,},},
        [3] = {{207,306,212,313,309,},{209,412,404,301,103,},{106,202,206,413,302,},{307,104,308,310,113,},{211,203,107,111,304,},},
        [4] = {{311,409,303,105,204,},{213,209,304,413,411,},{109,101,110,108,404,},{206,310,401,205,407,},{402,306,313,201,305,},},
        [5] = {{206,101,409,201,407,},{104,402,102,305,313,},{105,412,410,301,103,},{202,203,303,208,106,},{304,107,307,404,411,},},
    },    --闲1,2,4赢
    [21011] = {
        [1] = {{309,208,111,306,411,},{313,211,112,107,401,},{106,407,201,410,210,},{302,413,203,412,110,},{108,104,206,310,303,},},
        [2] = {{202,307,402,306,204,},{205,101,408,409,106,},{108,403,401,107,404,},{405,410,109,201,309,},{110,113,213,303,311,},},
        [3] = {{304,408,409,211,412,},{404,206,108,111,109,},{403,101,210,303,212,},{102,207,410,209,413,},{213,204,301,201,313,},},
        [4] = {{401,211,305,201,109,},{209,207,411,101,103,},{312,306,310,403,104,},{413,311,111,301,308,},{203,303,410,113,313,},},
        [5] = {{212,310,402,306,207,},{308,206,208,203,104,},{209,409,109,403,106,},{108,307,411,305,407,},{301,311,309,413,401,},},
    },    --闲1,3,4赢
    [20111] = {
        [1] = {{107,204,112,411,113,},{403,209,305,313,303,},{410,103,304,405,406,},{409,202,309,203,205,},{401,412,211,413,302,},},
        [2] = {{301,406,304,312,302,},{210,213,104,212,407,},{203,410,201,307,409,},{204,310,202,205,108,},{112,102,208,209,408,},},
        [3] = {{412,404,209,409,201,},{205,102,407,309,208,},{302,312,202,113,206,},{108,203,213,111,307,},{109,311,308,112,411,},},
        [4] = {{413,213,205,407,406,},{110,108,307,104,301,},{102,112,310,204,211,},{207,305,404,202,208,},{402,303,313,410,312,},},
        [5] = {{303,212,405,408,113,},{107,311,209,406,302,},{308,101,211,210,112,},{103,312,202,110,313,},{102,307,404,203,305,},},
    },    --闲2,3,4赢
    [21111] = {
        [1] = {{210,108,307,311,208,},{209,406,402,312,408,},{204,413,313,110,111,},{105,213,102,109,404,},{306,301,211,107,212,},},
        [2] = {{207,205,309,202,211,},{413,407,303,106,310,},{104,203,302,213,406,},{111,105,403,312,409,},{306,311,102,210,109,},},
        [3] = {{201,101,402,202,410,},{207,112,208,312,405,},{306,412,212,301,109,},{106,302,404,211,209,},{108,110,407,203,103,},},
        [4] = {{402,104,105,312,210,},{406,212,403,111,310,},{405,404,412,106,303,},{108,211,309,306,301,},{113,205,101,407,208,},},
        [5] = {{104,206,105,205,402,},{301,111,208,304,405,},{211,309,413,201,306,},{109,102,106,411,406,},{408,207,407,108,110,},},
    },    --闲1,2,3,4赢
    [20000] = {
        [1] = {{412,202,303,405,407,},{106,205,201,308,408,},{301,109,311,302,209,},{110,310,402,401,210,},{312,105,413,213,101,},},
        [2] = {{401,413,204,411,112,},{110,202,313,105,108,},{404,405,101,201,301,},{102,211,113,403,302,},{203,206,208,209,309,},},
        [3] = {{312,413,213,110,107,},{111,101,403,313,405,},{104,207,304,402,309,},{406,112,211,307,311,},{105,404,102,212,407,},},
        [4] = {{305,204,111,306,105,},{310,213,411,106,412,},{108,209,403,308,407,},{103,102,104,307,110,},{309,410,303,101,113,},},
        [5] = {{207,404,208,411,106,},{212,110,203,302,408,},{104,309,409,206,403,},{310,109,405,304,307,},{211,311,113,402,202,},},
    },    --庄通杀
}

-------------------------------
-------------------------------
---工具类

--获取牌类型,牌值
local function get_type_value_from_card(card)
    local ct = math.floor(card / 100)
    local cv = card % 100
    return ct,cv
end

--更新图标概率表
function SlotTool.update_picture_prob_list()
    local prob_list = {}

    local total_prob = 0
    local total_weight = SlotTool.calculate_total_weight(Weight_list)
    for id,w in pairs(Weight_list) do
        prob_list[id] = w / total_weight
        total_prob = total_prob + prob_list[id]
    end
        
    --总概率应为1
    if math.floor(total_prob * 100) ~= 100 then
        filelog.sys_error("total probability not equal to 1!",total_prob)
    end

    return prob_list,total_weight
end

--
--获取开奖类型
--返回 LotteryType类型
--
function SlotTool.get_lottery_type(gamename)
    --获取库存值
    local inventory = SlotTool.get_static_inventory_from_redis(gamename)

    local item = nil
    local s = inventory
    local a = 10000
    if s < -500 * a then
        item = S_list[1]
    elseif s >= -500 * a and s < -100 * a then
        item = S_list[2]
    elseif s >= -100 * a and s < -20 * a  then
        item = S_list[3]
    elseif s >= -20 * a and s < -10 * a then
        item = S_list[4]
    elseif s >= -10 * a and s < 200 * a then
        item = S_list[5]
    elseif s >= 200 * a and s < 1000 * a then
        item = S_list[6]
    elseif s >= 1000 * a and s < 5000 * a then
        item = S_list[7]
    elseif s >= 5000 * a and s < 10000 * a then
        item = S_list[8]
    elseif s >= 10000 * a then
        item = S_list[9]
    end

     --根据概率获取随机开奖类型
    local r = base.get_random(1, 1000)
    local hit = math.floor(item.hit * 1000)
    local nohit = hit + math.floor(item.nohit * 1000)
    local normal = nohit + math.floor(item.normal * 1000) 
    if r <= hit then
        return LotteryType.LOTTERY_TYPE_SYSTEM_LOSE
    elseif r <= nohit then
        return LotteryType.LOTTERY_TYPE_SYSTEM_WIN
    elseif r <= normal then
        return LotteryType.LOTTERY_TYPE_NORMAL
    end
end

--
--获取系统输赢列表
--
function SlotTool.get_system_win_lose_list(total_bet_list, total_bet, is_robot_banker)
    local sys_win_list = {}
    local sys_lose_list = {}

    if is_robot_banker then
        for id,_ in pairs(Weight_list) do
            local rtm = 0
            local bet_ids = Witem_odds_list[id] or {}
            for _,bet_id in pairs(bet_ids) do
                local odds = 2
                if odds > 0 and total_bet_list[bet_id] then
                    rtm = rtm + odds * (total_bet_list[bet_id] or 0)   --返钱数
                end
            end
            if rtm < total_bet then
                table.insert(sys_win_list,id)
            elseif rtm > total_bet then
                table.insert(sys_lose_list,id)
            end
        end
    else
        for id,_ in pairs(Weight_list) do
            local rtm = 0
            local bet_ids = Witem_odds_list[id] or {}
            for _,bet_id in pairs(bet_ids) do
                local odds = 2
                if odds > 0 and total_bet_list[bet_id] then
                    rtm = rtm + odds * (total_bet_list[bet_id] or 0)   --返钱数
                end
            end
            if rtm > total_bet then
                table.insert(sys_win_list,id)
            elseif rtm < total_bet then
                table.insert(sys_lose_list,id)
            end
        end
    end
    
    return sys_win_list,sys_lose_list
end

--
--检测是否为有牛牌型
--
local function check_is_cowcards(cards, sv)
    if not cards or #cards ~= 5 then
        return
    end

    local str = ""
    if not sv then
        sv = {}
        for _,v in pairs(cards) do
            local cv = v % 100
            table.insert(sv,cv)
        end
        table.sort(sv)
    end

    for _,cv in pairs(sv) do
        if cv < 10 then
            str = str .. cv
        else
            str = str .. 'A'
        end
    end
    
    return cowcards_list[str]
end

--
--获得牌型：同花顺牛，五小牛，五花牛，炸弹牛，葫芦牛，同花牛，顺子牛，牛一~牛牛，没牛
--17同花顺 16五小牛 15五花牛 14炸弹牛 13葫芦牛 12同花牛 11顺子牛 1~10牛一~牛牛 0没牛
--
function SlotTool.get_cards_type(cards, is_special)
    if not cards or #cards ~= 5 then
        return
    end

    local result = {}

    --排序牌值
    local cvs = {}
    local points = 0
    local maxcard = 0
    local specard = 0
    local is_samecolor = nil
    for _,v in pairs(cards) do
        local ct = math.floor(v / 100)
        local cv = v % 100
        table.insert(cvs,cv)
        is_samecolor = is_samecolor or ct
        if is_samecolor ~= ct then
            is_samecolor = 0
        end
        if cv > 10 then
            points = points + 10
        else
            points = points + cv
        end
        local mcv = maxcard % 100
        if mcv < cv then
            maxcard = v
        elseif mcv == cv and 
        math.floor(maxcard / 100) < ct then
            maxcard = v
        end
    end
    table.sort(cvs)

    --特殊牛
    local is_sz = false
    local is_th = false
    
     --检测特殊牛：顺子牛,同花牛,葫芦牛,同花顺牛
    if is_special then
        --判断是否为顺子牛
        if (cvs[5] - cvs[1] == 4 and cvs[4] - cvs[1] == 3)
        and (cvs[3] - cvs[1] == 2 and cvs[2] - cvs[1] == 1) then
            is_sz = true
            result.cards_type = SpecialPrize.SPECIAL_PRIZE_SHUNZI_NIU
        end

        --判断是否为同花牛
        if is_samecolor ~= 0 then
            is_th = true
            result.cards_type = SpecialPrize.SPECIAL_PRIZE_TONGHUA_NIU
        end

        --判断是否为葫芦牛
        if not is_th and not is_sz then
            if (cvs[1] == cvs[3] and cvs[4] == cvs[5]) 
            or (cvs[1] == cvs[2] and cvs[3] == cvs[5]) then
                is_hl = true
                result.cards_type = SpecialPrize.SPECIAL_PRIZE_HULU_NIU
            end
        end
    end

    --判断是否为炸弹牛
    if (cvs[1] == cvs[4] or cvs[2] == cvs[5]) then
        specard = cvs[2]
        result.cards_type = SpecialPrize.SPECIAL_PRIZE_ZHADAN_NIU
    end
    
    --判断是否为五花牛
    if cvs[1] > 10 then
        result.cards_type = SpecialPrize.SPECIAL_PRIZE_WUHUA_NIU
    end

    --判断是否为五小牛
    if (points < 11 and cvs[5] < 6) then
        result.cards_type = SpecialPrize.SPECIAL_PRIZE_WUXIAO_NIU
    end

    --判断是否为同花顺牛
    if is_th and is_sz then
        result.cards_type = SpecialPrize.SPECIAL_PRIZE_TONGHUASHUN_NIU
    end

    --判断是否为牛一~牛牛
    --任3张牌点数和为10,20或30即有牛
    --a + b + c = 10
    --a + b + c = 20
    --a + b + c = 30
    if not result.cards_type then
        local niu_num = check_is_cowcards(cards, cvs)
        if not niu_num then
            result.cards_type = SpecialPrize.SPECIAL_PRIZE_MEI_NIU
        else
            result.cards_type = niu_num
        end
    end

    --返回结果
    result.spe_card = specard
    result.max_card = maxcard
    result.points = points % 10
    if result.points == 0 then
        result.points = 10
    end

    return result
end

--比较玩家牌
--true 闲赢 false 庄赢
function SlotTool.compare_cards(banker_cards, player_cards)
    if not banker_cards or not player_cards then
        return
    end

    if banker_cards.cards_type ~= player_cards.cards_type then      --比较牌型
        return (banker_cards.cards_type < player_cards.cards_type)
    elseif banker_cards.cards_type == SpecialPrize.SPECIAL_PRIZE_ZHADAN_NIU then    --炸弹牛，比较炸弹大小
        return (banker_cards.spe_card < player_cards.spe_card)
    else    --牌型相同比较最大单牌
        local bcv = banker_cards.max_card % 100
        local pcv = player_cards.max_card % 100
        if bcv ~= pcv then return (bcv < pcv) end
        return (banker_cards.max_card < player_cards.max_card)
    end
end

--
--根据手牌，获得开奖结果
--
function SlotTool.get_random_result_by_cards(total_bet_list, gamename, total_bet, lotterytype, is_robot_banker)

    --检测结果
    local function check_result(result_list, total_bet_list, total_bet, loselimit, lotterytype, is_robot_banker)
        local all_results = result_list.all_results or {}
        local ext_prize_list = result_list.ext_prize_list or {}
        
        --通杀或通赔4/5概率重新获取
        local prize_killall = EBRNNExtraPrizeType.EXTRA_PRIZE_TYPE_KILLALL
        if ext_prize_list[1] == prize_killall or ext_prize_list[4] then
            if base.get_random(1,5) ~= 1 then
                return false
            end
        end
        
        --计算系统输赢
        local total_win = total_bet
        for _,id in pairs(ext_prize_list) do
            local bet_id = id
            local i = (id % 10) % 5 + 1
            local odds_item = Odds_list[id] or {}
            local cur_result = all_results[i] or {}
            local cards_type = cur_result.cards_type or 0
            local points = cur_result.points or 0
            local odds = odds_item[cards_type]
            if type(odds) == "table" then
                odds = odds[points] or odds[1] or 2
            end
            total_win = total_win - odds * (total_bet_list[bet_id] or 0)
        end

        if not is_robot_banker then
            total_win = -total_win
        end

        --判断是否超系统输上限
        local is_max_loselimit = false
        if total_win < -loselimit then
            is_max_loselimit = true
        end
        
        --不超过输上限
        if not is_max_loselimit then
            if lotterytype == LotteryType.LOTTERY_TYPE_NORMAL then
                return true
            elseif total_win > 0 and lotterytype == LotteryType.LOTTERY_TYPE_SYSTEM_WIN then
                return true
            elseif total_win < 0 and lotterytype == LotteryType.LOTTERY_TYPE_SYSTEM_LOSE then
                return true
            end
        end

        return false
    end

    ---------------------

    local loselimit = SlotTool.get_system_lose_limit(gamename)

    --除12345外的其他21种牌组合
    local all_swaps = {
        54321,23451,31254,43521,13542,24315,
        21453,25314,23541,32415,31542,53124,
        15342,35214,34521,41235,35412,43215,
        32145,42135,14523,52431,25143,
    }

    local cnt = 0
    while cnt < 20 do
        local result_list = SlotTool.get_real_random_result()
        local is_ok = check_result(result_list,total_bet_list,total_bet,loselimit,lotterytype,is_robot_banker)
        if is_ok then
            return result_list
        end

        --交换牌型，再次检测
        local all_rand_cards = tabletool.deepcopy(result_list.all_cards)
        for _,val in pairs(all_swaps) do
            local k = 10000
            local cur_rand_cards = {}
            for  i = 1,5 do
                local idx = math.floor(val / k) % 10
                cur_rand_cards[i] = all_rand_cards[idx]
                k = math.floor(k / 10)
            end
            result_list = SlotTool.get_real_random_result(cur_rand_cards)
            is_ok = check_result(result_list,total_bet_list,total_bet,loselimit,lotterytype,is_robot_banker)
            if is_ok then
                return result_list
            end
        end
        cnt = cnt + 1
    end

    return false
end

--
--获得系统输钱上限
--
function SlotTool.get_system_lose_limit(gamename)
    local loselimit = 0
    local S = SlotTool.get_static_inventory_from_redis(gamename)
    if S < 0 then
        loselimit = SystemLoseLimit_Base
    else
        loselimit = math.floor(S * SystemLoseLimit_Factor) + SystemLoseLimit_Base
    end

    return loselimit
end

--
--获取系统必输随机结果
--去除超上限项
--
function SlotTool.get_mustlose_random_result(sys_lose_list, total_bet_list, gamename, total_bet, is_robot_banker)
    local loselimit = SlotTool.get_system_lose_limit(gamename)

    --去除超上限亏损
    if sys_lose_list and #sys_lose_list > 0 then
        local lose_w_list = {}
        local total_weight = 0
        for _,id in pairs(sys_lose_list) do
            local rtm = 0
            local bet_ids = Witem_odds_list[id] or {}
            for _,bet_id in pairs(bet_ids) do
                local odds = 2
                rtm = rtm + odds * (total_bet_list[bet_id] or 0)
            end
            local ksz = total_bet - rtm
            if (is_robot_banker and ksz >= -loselimit)  
            or (not is_robot_banker and ksz <= loselimit) then
                lose_w_list[id] = Weight_list[id]
                total_weight = total_weight + lose_w_list[id]
            end
        end

        if next(lose_w_list) ~= nil then
            return SlotTool.get_random_result_by_weightlist(lose_w_list,total_weight)
        else
            return SlotTool.get_min_spin_result(total_bet_list,is_robot_banker)
        end
    else
        --当前押注使系统必定赢，则选择玩家赢钱最多的结果
        return SlotTool.get_max_spin_result(total_bet_list,is_robot_banker)
    end
end

--
--获取系统必赢随机结果
--
function SlotTool.get_mustwin_random_result(sys_win_list, total_bet_list, is_robot_banker)
   if sys_win_list and #sys_win_list > 0 then
        local win_w_list = {}
        local total_weight = 0
        for _,id in pairs(sys_win_list) do
            win_w_list[id] = Weight_list[id]
            total_weight = total_weight + win_w_list[id]
        end
        
        local id = SlotTool.get_random_result_by_weightlist(win_w_list,total_weight)
        return id
    end

    --当前押注使系统必输，则选择玩家赢钱最少的结果
    return SlotTool.get_min_spin_result(total_bet_list,is_robot_banker)
end

--
--获取普通随机结果
--去掉系统超上限亏损项
--
function SlotTool.get_normal_random_result(sys_lose_list, total_bet_list, gamename, total_bet, is_robot_banker)
    local loselimit = SlotTool.get_system_lose_limit(gamename)
    local random_id_list = tabletool.deepcopy(Weight_list)

    --去除超上限亏损
    if sys_lose_list and #sys_lose_list > 0 then
        for _,id in pairs(sys_lose_list) do
            local rtm = 0
            local bet_ids = Witem_odds_list[id] or {}
            for _,bet_id in pairs(bet_ids) do
                local odds = 2
                rtm = rtm + odds * (total_bet_list[bet_id] or 0)
            end
            local ksz =  total_bet - rtm
            if is_robot_banker and ksz < -loselimit then
                random_id_list[id] = nil
            elseif not is_robot_banker and ksz > loselimit then
                random_id_list[id] = nil
            end
        end
    end

    --所有项超上限，则返回最小的
    if next(random_id_list) == nil then
        return SlotTool.get_min_spin_result(total_bet_list,is_robot_banker)
    end

    --产生随机结果
    return SlotTool.get_random_result_by_weightlist(random_id_list)
end

--
--获得纯随机结果
--
function SlotTool.get_real_random_result(all_rand_cards)
    local all_cards = {}
    local card_num = (#CardData * CardPairNum) - CardOffset

    --随机获得一张不重复牌
    local function get_random_card_from_cardstack(num)
        local card = nil
        local r = base.get_random(1,num)
        r = (r - 1) % num + 1
        card = CardData[r]
        CardData[r] = CardData[num]
        CardData[num] = card
        return card
    end
    ----------------

    if not all_rand_cards then
        --随机发25张
        for i = 1,5 do
            for j = 1,5 do
                local card = get_random_card_from_cardstack(card_num)
                all_cards[j] = all_cards[j] or {}
                table.insert(all_cards[j],card)
                card_num = card_num - 1
            end
        end
    else
        all_cards = all_rand_cards
    end
    
    --获得牌型
    local prize_id = 0
    local prize_list = {}
    local all_results = {}
    for i,cards in pairs(all_cards) do
       all_results[i] = SlotTool.get_cards_type(cards)
    end

    --判定开奖结果，第一副牌为庄家牌，其他4副为闲家
    for i = 2,5 do
        local is_win = SlotTool.compare_cards(all_results[1],all_results[i])
        all_results[i].is_win = is_win
        if is_win then
            table.insert(prize_list, Picture_id[i-1])
        end
    end

    --庄通杀
    if #prize_list == 0 then
        table.insert(prize_list, EBRNNExtraPrizeType.EXTRA_PRIZE_TYPE_KILLALL)
    end

    --返回结果
    local result_list = {
        all_cards = all_cards,
        prize_id = 0,
        ext_prize_list = prize_list,
        all_results = all_results,
    }

    return result_list
end

--
--获得可能的随机结果
--
function SlotTool.get_may_random_result(result_id)
    local all_cards = {}
    local real_all_cards = {}
    local card_num = (#CardData * CardPairNum) - CardOffset

    --随机获得一张不重复牌
    local function get_random_card_from_cardstack(num)
        local card = nil
        local r = base.get_random(1,num)
        r = (r - 1) % num + 1
        card = CardData[r]
        CardData[r] = CardData[num]
        CardData[num] = card
        return card
    end

    --5副牌由小到大排列
    local function compare(cur_cards, last_cards)
        if not cur_cards or not last_cards then
            return false
        end

       return SlotTool.compare_cards(cur_cards.results,last_cards.results)
    end
    -------------------------------

    --获得获胜玩家id
    local max = 5
    local win_ids = {[1101] = 0, [1102] = 0, [1103] = 0, [1104] = 0, [1105] = 0}
    local win_list = Witem_odds_list[result_id] or {}
    for _,player_id in pairs(win_list) do
        win_ids[player_id] = max
        max = max - 1
    end
    if win_ids[1105] == 0 then
        win_ids[1105] = max
        max = max - 1
    end
    
   --随机发5副非特殊牌
    for i = 1,5 do
        while true do
            local card1 = get_random_card_from_cardstack(card_num)
            local card2 = get_random_card_from_cardstack(card_num-1)
            local card3 = get_random_card_from_cardstack(card_num-2)
            local card4 = get_random_card_from_cardstack(card_num-3)
            local card5 = get_random_card_from_cardstack(card_num-4)
            local cur_cards = {card1,card2,card3,card4,card5}
            local cards_result = SlotTool.get_cards_type(cur_cards)
            if cards_result.cards_type <= SpecialPrize.SPECIAL_PRIZE_NIU_NIU then
                all_cards[i] = {cards = cur_cards, results = cards_result}
                card_num = card_num - 5
                break
            end
        end
    end

    --由小到大排列牌
    table.sort(all_cards,compare)

    --给玩家发牌
    for i = 1,5 do
        local k = i % 5 + 1
        local id = 1100 + i
        local idx = win_ids[id]
        if idx == 0 then
            local r = base.get_random(1,max)
            real_all_cards[k] = all_cards[r]
            all_cards[r] = all_cards[max]
            all_cards[max] = real_all_cards[k]
            max = max - 1
        else
            real_all_cards[k] = all_cards[idx]
        end
    end

    ------------------------------
    --获得实际手牌和牌型
    local prize_id = 0
    local prize_list = {}
    local all_results = {}
    local prize_flags = {}
    local all_result_cards = {}
    for i,item in pairs(real_all_cards) do
       all_results[i] = item.results
       all_result_cards[i] = item.cards
    end

    --判定开奖结果，第一副牌为庄家牌，其他4副为闲家
    for i = 2,5 do
        local is_win = SlotTool.compare_cards(all_results[1],all_results[i])
        all_results[i].is_win = is_win
        if is_win then
            prize_flags[Picture_id[i-1]] = true
            table.insert(prize_list, Picture_id[i-1])
        end
    end

    --庄通杀
    if #prize_list == 0 then
        prize_flags[Picture_id[5]] = true
        table.insert(prize_list, EBRNNExtraPrizeType.EXTRA_PRIZE_TYPE_KILLALL)
    end

    --检测结果
    local is_ok = true
    for _,win_id in pairs(win_list) do
        if not prize_flags[win_id] then
            is_ok = false
            break
        end
    end
    
    --结果不相同，返回固定牌
    if not is_ok then
        local profile_cards = Profile_Cards_List[result_id]
        local r = base.get_random(1,#profile_cards)
        all_result_cards = tabletool.deepcopy(profile_cards[r])
        for i,cards in pairs(all_result_cards) do
            all_results[i] = SlotTool.get_cards_type(cards)
        end

        prize_list = {}
        for i = 2,5 do
            local is_win = SlotTool.compare_cards(all_results[1],all_results[i])
            all_results[i].is_win = is_win
            if is_win then
                table.insert(prize_list, Picture_id[i-1])
            end
        end

        --庄通杀
        if #prize_list == 0 then
            table.insert(prize_list, EBRNNExtraPrizeType.EXTRA_PRIZE_TYPE_KILLALL)
        end
    end

    --返回结果
    local result_list = {
        all_cards = all_result_cards,
        prize_id = 0,
        ext_prize_list = prize_list,
        all_results = all_results,
    }

    return result_list
end

--
--产生一个随机旋转结果
--
function SlotTool.gen_random_spin_result(gamename, total_bet_list, total_bet, avg_bet, is_robot_banker, is_random, banker_round)
    local result_id = nil
    local result_list = nil

    --计算系统输赢列表
    local sys_win_list,sys_lose_list = SlotTool.get_system_win_lose_list(total_bet_list,total_bet,is_robot_banker)

    --随机开奖
    if is_random then
        return SlotTool.get_real_random_result()
    else
        --获取开奖类型,分：系统必赢，系统必输，随机开奖3种
        local lottery_type = SlotTool.get_lottery_type(gamename)
        result_list = SlotTool.get_random_result_by_cards(total_bet_list,gamename,total_bet,lottery_type,is_robot_banker)
        if result_list then
            return result_list
        end

        if lottery_type == LotteryType.LOTTERY_TYPE_SYSTEM_WIN then     --系统必赢
            result_id = SlotTool.get_mustwin_random_result(sys_win_list,total_bet_list,is_robot_banker)
        elseif lottery_type == LotteryType.LOTTERY_TYPE_SYSTEM_LOSE then  --系统必输
            result_id = SlotTool.get_mustlose_random_result(sys_lose_list,total_bet_list,gamename,total_bet,is_robot_banker)
        else    --随机开奖
            result_id = SlotTool.get_normal_random_result(sys_lose_list,total_bet_list,gamename,total_bet,is_robot_banker)
        end
    end

    --根据开牌结果获取随机牌
    local result_list = SlotTool.get_may_random_result(result_id)

    return result_list
end

--
--获取最小奖励
--
function SlotTool.get_min_spin_result(total_bet_list, is_robot_banker)
    local min_id = 0
    local min_rtm = 100000000000
    if not is_robot_banker then
        min_rtm = 0
    end
    
    --循环每一种情况,求返钱数最小的
    for id,_ in pairs(Weight_list) do
        local rtm = 0
        local bet_ids = Witem_odds_list[id] or {}
        for _,bet_id in pairs(bet_ids) do
            local odds = 2
            if odds > 0 and total_bet_list[bet_id] then
                rtm = rtm + odds * (total_bet_list[bet_id] or 0)   --返钱数
            end
        end
        if is_robot_banker then
            if min_rtm > rtm then
                min_rtm = rtm
                min_id = id
            end
        else
            if min_rtm < rtm then
                min_rtm = rtm
                min_id = id
            end
        end
        
    end
    
    return min_id
end

--
--获取最大奖励
--
function SlotTool.get_max_spin_result(total_bet_list, is_robot_banker)
    local max_id = 0
    local max_rtm = 0
    if not is_robot_banker then
        max_rtm = 100000000000
    end
    
    --循环每一种情况,求返钱数最大的
    for id,_ in pairs(Weight_list) do
        local rtm = 0
        local bet_ids = Witem_odds_list[id] or {}
        for _,bet_id in pairs(bet_ids) do
            local odds = 2
            if odds > 0 and total_bet_list[bet_id] then
                rtm = rtm + odds * (total_bet_list[bet_id] or 0)   --返钱数
            end
        end
        if is_robot_banker then
            if max_rtm < rtm then
                max_rtm = rtm
                max_id = id
            end
        else
            if max_rtm > rtm then
                max_rtm = rtm
                max_id = id
            end
        end
    end
    
    return max_id
end


--
--检测随机结果的正确性
--
function SlotTool.check_random_spin_result(spin_result)
    if not spin_result then
        return false
    end

    --检测是否有同牌
    local flags = {}
    local max_same = 1
    for _,cards in pairs(spin_result.all_cards) do
        for _,card in pairs(cards) do
            if flags[card] == max_same then
                filelog.sys_error("-----------have same card------",spin_result)
                return false
            end
            flags[card] = (flags[card] or 0) + 1
        end
    end
  
    return true
end

--
--处理送灯
--is_seq是否为连续灯
--
function SlotTool.handle_give_lamp(sd_w_list, is_seq)
    local result_list = {}

    --获得送灯数
    local lamp_num = SlotTool.get_random_result_by_weightlist(sd_w_list)
    if not lamp_num then
        return
    end

    --计算总权值
    local total_w = SlotTool.calculate_total_weight(SDFruit_weight_list)

    --随机获取lamp_num盏灯
    if is_seq then  --连续lamp_num盏灯
        local id = SlotTool.get_random_result_by_weightlist(SDFruit_weight_list,total_w)
        table.insert(result_list,id)
        table.insert(result_list,lamp_num)
    else
        for i = 1,lamp_num do
            local id = SlotTool.get_random_result_by_weightlist(SDFruit_weight_list,total_w)
            table.insert(result_list,id)
        end
    end
    
    return result_list
end

--
--处理闪电
--
function SlotTool.handle_lightning(lgtn_w_list)
    local result_list = {}

    --获得翻倍数
    local rate_num = SlotTool.get_random_result_by_weightlist(lgtn_w_list)
    if not rate_num then
        return
    end
    table.insert(result_list,rate_num)

    return result_list
end

--
--根据随机结果获取额外奖励项
--
function SlotTool.get_ext_prize_item(prize_id)
    
end

--
--保存奖励记录
--
function SlotTool.save_prize_records(gamename, opencard_result)
    local records = {}
    local key = (gamename or "") .. "_prize_records"
    local result,data = redisdao.query_data(".gmmqredis", "get", key)
    if result and data then
        records = json.decode(data) or {}
    end
    
    for _,prize_id in pairs(opencard_result) do
        local id = tostring(prize_id)
        records[id] = (tonumber(records[id]) or 0) + 1
    end
    records.total_count = (tonumber(records.total_count) or 0) + 1
    redisdao.query_data(".gmmqredis", "set", key, json.encode(records))

    ---------------------------------

    --辅助函数1
    local function helper_func(val)
        local cnt = 0
        local tmp = val
        while val >= 10 do
            val = math.floor(val / 10)
            cnt = cnt + 1
        end
        if math.floor(10^cnt) == tmp then
            return true
        end
        return false
    end

    --辅助函数2
    local function func(records)
        local porp_list = {}
        local subprop_list = {}
        local cnt = records.total_count or 0
        if cnt == 0 then
            return
        end

        for k,v in pairs(records) do
            if type(v) ~= "table" and k ~= "total_count" then
                v = tonumber(v) or 0
                porp_list[k] = string.format("%g%%",math.floor(v / cnt * 10000) / 100)
            elseif k == "total_count" then
                porp_list[k] = v
            else
                subprop_list[k] = func(v)
            end
        end
        return porp_list,subprop_list
    end

    --开奖次数每增加10倍，统计一次概率
    if helper_func(records.total_count) then
        local porp_list,subprop_list = func(records)
        filelog.sys_obj("prop_list", records.total_count, porp_list, "=================\n", subprop_list)
    end
    ---------------

    return true
end

--
--创建格式化赔率列表
--
function SlotTool.create_format_odds_list()
    local fmt_odds_list = {}

    for id,odds_list in pairs(Odds_list) do
        for cardstype,odds in pairs(odds_list) do
            local val = tonumber(id) * 10000 + cardstype * 100 + tonumber(odds)
            table.insert(fmt_odds_list,val)
        end
    end
    
    return fmt_odds_list
end

--
--保存赔率列表到文件
--
function SlotTool.save_odds_list_to_file()
    local f = io.open("odds_list.lua","w+")
    if not f then
        filelog.print("open file error!")
        return
    end

    f:write("return { \n")
    for id,odds_list in pairs(Odds_list) do
        for cardstype,odds in pairs(odds_list) do
            local val = tonumber(id) * 10000 + cardstype * 100 + tonumber(odds)
            f:write(tostring(val) .. ",")
        end
    end
    f:write("}")
    f:close()
end

--
--创建预存牌堆
--
function SlotTool.create_profile_cards_list(n)
    n = n or 5

    Profile_Cards_List = {}
    for id,_ in pairs(Weight_list) do
        for i = 1,n do
            local result_list = SlotTool.get_may_random_result(id)
            Profile_Cards_List[id] = Profile_Cards_List[id] or {}
            Profile_Cards_List[id][i] = result_list.all_cards
        end
    end
    
    local str = "{\n"
    for id,vs in pairs(Profile_Cards_List) do
        str = str .. "[" .. id .. "] = {\n"
        for i,all_cards in pairs(vs) do
            str = str .. "[" .. i .. "] = {" 
            for _,cards in ipairs(all_cards) do
                str = str .. "{"
                for _,v in ipairs(cards) do
                    str = str .. v .. ","
                end
                str = str .. "},"
            end
            str = str .. "},\n"
        end
        str = str .. "},\n"
    end
    str = str .. "}\n"
    
    filelog.sys_info(str)
end

-------------------------------
----------
--外部接口

local CMD = {}

local cs = queue()

-----------------
----

--
--获取随机旋转结果
--total_bet_list 总下注列表
--total_bet 总下注值
--avg_bet 平均下注值
--is_robot_banker 是否机器人做庄
--is_random 是否随机开奖
--banker_round 已做庄局数
--
function CMD.get_random_spin_result(gamename, total_bet_list, total_bet, avg_bet, is_robot_banker, is_random, banker_round)
    local cnt = 0
    while cnt < 100 do
        local isok,spin_result = skynet.pcall(SlotTool.gen_random_spin_result,gamename,total_bet_list,total_bet,avg_bet,is_robot_banker, is_random, banker_round)
        if isok and SlotTool.check_random_spin_result(spin_result) then
            return spin_result
        end
        cnt = cnt + 1
    end

    return false
end

--
--根据随机结果获取额外奖励
--
function CMD.get_ext_prize_result(prize_id)
    local ext_prize_result = {}

    --根据id获取奖励项
    local item = SlotTool.get_ext_prize_item(prize_id)
    if not item then
        return
    end

    --计算总权值
    local total_w = 0
    local w_list = {}
    for key,val in pairs(item) do
        if type(key) == "string" and string.sub(key,-1) == "w" then
            total_w = total_w + val
            w_list[key] = val
        end
    end
    
    --根据权值表，获取随机结果
    local key = SlotTool.get_random_result_by_weightlist(w_list,total_w)
    if not key or key == "failed_w" then
        return
    end

    --获取额外奖励类型
    local len = string.len(key)
    local extprize_name = string.sub(key,1,len - 2)
    local extprize_type = Extra_prize_type[extprize_name]
    if not extprize_type then
        return
    end

    --获取奖励
    local extprize_list = nil
    
    --返回结果
    ext_prize_result.extprize_type = extprize_type
    ext_prize_result.extprize_list = extprize_list

    return ext_prize_result
end

--
--获取开局奖励
--
function CMD.get_start_prize_result(rids)
    local prize_result_list = {}

    if true then
        return {}
    end

    --获取随机结果
    local function get_random_result(prize_list)
        --计算总权值
        local total_w = 0
        local w_list = {}
        for key,val in pairs(prize_list) do
            if type(key) == "string" and string.sub(key,-1) == "w" then
                total_w = total_w + val
                w_list[key] = val
            end
        end
    
        --根据权值表，获取随机结果
        local key = SlotTool.get_random_result_by_weightlist(w_list,total_w)

        return key
    end

    -------------------

     --开火车奖励表
    local drivetrain_list = SPrize_weight_list[SpecialPrize.SPECIAL_PRIZE_KHC]

    --根据权值表，获取随机结果
    local key = get_random_result(drivetrain_list)
    if not key or key == "failed_w" then
        
    else
        local extprize_list = SlotTool.handle_give_lamp(drivetrain_list.sd_w_list,true)
        local item = {
            extprize_type = Extra_prize_type.drivetrain,
            extprize_list = extprize_list,
        }
        table.insert(prize_result_list,item)
    end

    ------------------

    rids = rids or {}
    
    --低于10人不触发
    local player_num = #rids
    if player_num < 10 then
        return prize_result_list
    end

     --判断是否触发鸿运当头
    local goodluck_list = SPrize_weight_list[SpecialPrize.SPECIAL_PRIZE_HYDT]
    local key = get_random_result(goodluck_list)
    if not key or key == "failed_w" then
        return prize_result_list
    end

    --随机选取10%的人中奖
    local prize_coin_list = {}
    local total_w = SlotTool.calculate_total_weight(goodluck_list.coin_w_list)
    local hit_num = math.floor(player_num * 0.1)
    for i = 1,hit_num do
        local k = base.get_random(1,player_num)
        local rid = rids[k]
        local coin_num = SlotTool.get_random_result_by_weightlist(goodluck_list.coin_w_list,total_w)

        prize_coin_list[rid] = coin_num
        rids[k] = rids[player_num]
        table.remove(rids)
        player_num = #rids
    end
    
    if hit_num > 0 then
        local item = {
            extprize_type = Extra_prize_type.goodluck,
            extprize_list = prize_coin_list,
        }
        table.insert(prize_result_list,item)
    end
 
    return prize_result_list
end

--
--处理开奖
--
function CMD.handle_open_jackpot(gamename, jackpot_id, player_list)
    local award_list = {}

    --获取奖池金额
    local jackpot_money = SlotTool.get_jackpot_from_redis(gamename,jackpot_id)

    --随机开奖
    local total_coin = 0
    local max_level = 6
    for _,item in pairs(player_list) do
        local level = math.floor(item.game_num / 5)
        if level > max_level then
            level = max_level
        end
        local w_list = Jackpot_weight_list[level]
        local award_id = SlotTool.get_random_result_by_weightlist(w_list)
        local award_coin = math.floor(Jackpot_award_list[award_id] * jackpot_money * 0.01)
        local award_item = {
            rid = item.rid,
            logo = item.logo,
            rolename = item.rolename,
            award_money_num = award_coin,
        }
        table.insert(award_list, award_item)
        total_coin = total_coin + award_coin
    end
    
    return award_list,total_coin
end

--
--保存奖励记录
--
function CMD.save_prize_records(gamename, opencard_result)
  return cs(SlotTool.save_prize_records,gamename,opencard_result)
end

--
--处理庄家收益
--
function CMD.handle_banker_profit(ganmename, total_bet_num, player_win_num)
    local banker_win = total_bet_num - player_win_num
    return banker_win
end

--
--更新图标权值表
--
function CMD.update_picture_weight_list(new_w_list)
    if type(new_w_list) ~= "table" then
        return false
    end

    for k,v in pairs(new_w_list) do
        if Weight_list[k] and v >= 0 then
           Weight_list[k] = v
        end
    end
    
    --更新化概率表,总权值
    if next(new_w_list) ~= nil then
        Prob_list,Total_weight_list = SlotTool.update_picture_prob_list()
    end

    return true
end

--
--设置系统输钱上限
--
function CMD.set_system_lose_limit(loselimit_base, loselimit_factor)
    loselimit_base = loselimit_base or 0
    loselimit_factor = loselimit_factor or 0.02
    if loselimit_base < 0 or loselimit_factor < 0 then
        return false
    end
    SystemLoseLimit_Base = loselimit_base
    SystemLoseLimit_Factor = loselimit_factor

    return true
end

--
--获取格式化赔率列表
--
function CMD.get_format_odds_list()
    return SlotTool.create_format_odds_list()
end

--
--处理结算结果
--@total_change 总变化值
--@total_water  总流水值
--@total_bet    玩家总下注
--
function CMD.handle_balance_result(gamename, total_change, total_water, total_bet, comment)
    local tax_rate = SlotTool.get_tax_rate_from_redis(gamename)
    local profit_val = math.floor(total_bet * tax_rate * 100) / 100
    local inventory_val = -total_change

    --更新收益值
    local result1 = SlotTool.update_system_profit(gamename, profit_val, comment)
    if result1 then
        inventory_val = inventory_val - profit_val
    end

    --更新库存值，扣除抽水
    local service_fee_rate = SlotTool.get_service_fee_rate_from_redis(gamename)
    local service_fee_val = math.floor(total_water * service_fee_rate * 100) / 100
    inventory_val = inventory_val - service_fee_val

    return SlotTool.update_system_inventory(gamename, inventory_val, comment)
end

--
--获取抽水率
--
function CMD.get_service_fee_rate(gamename)
    return SlotTool.get_service_fee_rate_from_redis(gamename)
end

-----------
--
--初始化
--
local function init()

    --初始化概率表,总权值
    Prob_list,Total_weight = SlotTool.update_picture_prob_list()
    
    --[[
    --保存赔率列表到文件
    SlotTool.save_odds_list_to_file()

    filelog.sys_info("init slot tool ok!")

    --检测预存牌
    for id,cards_list in pairs(Profile_Cards_List) do
        for k,all_cards in pairs(cards_list) do
            --获得牌型
            local all_results = {}
            for i,cards in ipairs(all_cards) do
               all_results[i] = SlotTool.get_cards_type(cards)
            end

            --判定开奖结果，第一副牌为庄家牌，其他4副为闲家
            local mlt = 1000
            local key = 20000
            for i = 2,5 do
                local is_win = SlotTool.compare_cards(all_results[1],all_results[i])
                all_results[i].is_win = is_win
                if is_win then
                    key = key + mlt
                end
                mlt = math.floor(mlt / 10)
            end
            if key ~= id then
                filelog.sys_info("check profile cards error!")
                return
            end
            if not SlotTool.check_random_spin_result({all_cards = all_cards}) then
                return
            end
        end
    end
    filelog.sys_info("check profile cards ok!")
    --]]
    
end

-------------------
--
skynet.start(function()
    init()
    skynet.dispatch("lua",function(session, source, cmd, ...)
        local f = CMD[cmd]
        if f then
            skynet.retpack(f(...))
        else
            skynet.retpack()
        end
    end)
end)